# 存储指令对应的二进制代码
CR_instruction = {'c.add': ['10', '1001'],
                  'c.mv': ['10', '1000'],
                  'c.jr': ['10', '1000'],
                  'c.jalr': ['10', '1001']
                  }
CI_instruction = {'c.lwsp': ['10', '010'],
                  'c.flwsp': ['10', '011'],
                  'c.fldsp': ['10', '001'],
                  'c.addi': ['01', '000'],
                  'c.addi16sp': ['01', '011'],
                  'c.li': ['01', '010'],
                  'c.lui': ['01', '011'],
                  'c.slli': ['10', '000'],
                  'c.nop': ['01', '000'],
                  'c.ebreak': ['10', '100']
                  }
CSS_instruction = {'c.swsp': ['10', '110'],
                   'c.fswsp': ['10', '111'],
                   'c.fsdsp': ['10', '101']
                   }
CIW_instruction = {'c.addi4spn': ['00', '000']}
CL_instruction = {'c.lw': ['00', '010'],
                  'c.flw': ['00', '011'],
                  'c.fld': ['00', '001']
                  }
CS_instruction = {'c.sw': ['00', '110'],
                  'c.fsw': ['00', '111'],
                  'c.fsd': ['00', '101']
                  }
CA_instruction = {'c.and': ['01', '11', '100011'],
                  'c.or': ['01', '10', '100011'],
                  'c.xor': ['01', '01', '100011'],
                  'c.sub': ['01', '00', '100011']
                  }
CB_instruction = {'c.beqz': ['01', '110'],
                  'c.bnez': ['01', '111'],
                  'c.srli': ['01', '00', '100'],
                  'c.srai': ['01', '01', '100'],
                  'c.andi': ['01', '10', '100']
                  }
CJ_instruction = {'c.j': ['01', '101'],
                  'c.jal': ['01', '001']
                  }

instructionFormat = {'CR_instruction': ['c.add', 'c.mv', 'c.jr', 'c.jalr'],
                     'CI_instruction': ['c.lwsp', 'c.flwsp', 'c.fldsp', 'c.addi', 'c.addi16sp', 'c.li', 'c.lui', 'c.slli', 'c.nop', 'c.ebreak'],
                     'CSS_instruction': ['c.swsp', 'c.fswsp', 'c.fsdsp'],
                     'CIW_instruction': ['c.addi4spn'],
                     'CL_instruction': ['c.lw', 'c.flw', 'c.fld'],
                     'CS_instruction': ['c.sw', 'c.fsw', 'c.fsd'],
                     'CA_instruction': ['c.and', 'c.or', 'c.xor', 'c.sub'],
                     'CB_instruction': ['c.beqz', 'c.bnez', 'c.srli', 'c.srai', 'c.andi'],
                     'CJ_instruction': ['c.j', 'c.jal']}

instructionFormatChoice = {'CR_instruction': CR_instruction,
                           'CI_instruction': CI_instruction,
                           'CSS_instruction': CSS_instruction,
                           'CIW_instruction': CIW_instruction,
                           'CL_instruction': CL_instruction,
                           'CS_instruction': CS_instruction,
                           'CA_instruction': CA_instruction,
                           'CB_instruction': CB_instruction,
                           'CJ_instruction': CJ_instruction}

instructionMapping = {'00': {}, '01': {}, '10': {}, '11': {}}


def mappingInstruction():
    for k, v in instructionFormatChoice.items():
        for k_instruction, v_instruction in v.items():
            if v_instruction[0] in instructionMapping.keys():
                if len(v_instruction[-1]) != 3:
                    if v_instruction[-1][:3] in instructionMapping[v_instruction[0]].keys():
                        instructionMapping[v_instruction[0]][v_instruction[-1][:3]].append(k_instruction)
                    else:
                        instructionMapping[v_instruction[0]][v_instruction[-1][:3]] = []
                        instructionMapping[v_instruction[0]][v_instruction[-1][:3]].append(k_instruction)
                else:
                    if v_instruction[-1] in instructionMapping[v_instruction[0]].keys():
                        instructionMapping[v_instruction[0]][v_instruction[-1]].append(k_instruction)
                    else:
                        instructionMapping[v_instruction[0]][v_instruction[-1]] = []
                        instructionMapping[v_instruction[0]][v_instruction[-1]].append(k_instruction)

    return instructionMapping


instructionMapping = mappingInstruction()


def findRegId(regname):
    if regname in regName2Index.keys():
        return regName2Index[regname]
    elif regname in regABIName2Index.keys():
        return regABIName2Index[regname]

def CR_type_Format(data_list):
    """
    CR格式指令转换位二进制代码，data_list中为转换好的字段值
    :param data_list:
    :return:
    """
    return "{:04b}{:05b}{:05b}{:02b}".format(data_list[3], data_list[2], data_list[1], data_list[0])


def CR_convertInstruction2Binary(instruction):
    """
    用于实现CR格式指令到二进制代码的转换
    :param instruction:
    :return: instruction：
    """
    for k, v in CR_instruction.items():
        if k == instruction[0]:
            instruction[0] = v[0]
            instruction.append(v[1])
            if k == 'c.jr' or k == 'c.jalr':
                rs1 = findRegId(instruction[1])
                rs2 = 0
                op = int(instruction[0], 2)
                func4 = int(instruction[2], 2)
                instruction = [op, rs2, rs1, func4]
                pass
            else:
                # print(instruction)
                rd = findRegId(instruction[1])
                rs2 = findRegId(instruction[2])
                op = int(instruction[0], 2)
                func4 = int(instruction[3], 2)
                instruction = [op, rs2, rd, func4]
            return CR_type_Format(instruction)


def CI_type_Format(data_list):
    return "{:03b}{:01b}{:05b}{:05b}{:02b}".format(data_list[4], data_list[3], data_list[2], data_list[1], data_list[0])


def CI_convertInstruction2Binary(instruction):
    """
    用于实现指令到二进制代码的转换
    :param instruction:
    :return: instruction：
    """
    for k, v in CI_instruction.items():
        if k == instruction[0]:
            instruction[0] = v[0]
            instruction.append(v[1])
            if k == 'c.addi16sp':
                rd = 2
                imm = "{:06b}".format(int(instruction[1]))
                imm_high = int(imm[0], 2)
                imm_low = int(imm[1:], 2)
                op = int(instruction[0], 2)
                func3 = int(instruction[2],2)
                instruction = [op, imm_low, rd, imm_high, func3]
            elif k == 'c.nop':
                rd = 0
                imm = "{:06b}".format(int(instruction[1]))
                imm_high = int(imm[0], 2)
                imm_low = int(imm[1:], 2)
                op = int(instruction[0], 2)
                func3 = int(instruction[2], 2)
                instruction = [op, imm_low, rd, imm_high, func3]
                print(instruction)
            elif k == 'c.ebreak':
                rd = 0
                imm_low = 0
                imm_high = 0
                op = int(instruction[0], 2)
                func3 = int(instruction[1], 2)
                instruction = [op, imm_low, rd, imm_high, func3]
                print(instruction)
            else:
                instruction[1] = findRegId(instruction[1])
                op = int(instruction[0], 2)
                imm = "{:06b}".format(int(instruction[2]))
                imm_high = int(imm[0], 2)
                imm_low = int(imm[1:], 2)
                rd = instruction[1]
                func3 = int(instruction[3], 2)
                instruction = [op, imm_low, rd, imm_high, func3]
                print(instruction)
            return CI_type_Format(instruction)


def CSS_type_Format(data_list):
    return "{:03b}{:06b}{:05b}{:02b}".format(data_list[3], data_list[2], data_list[1], data_list[0])


def CSS_convertInstruction2Binary(instruction):
    """
    用于实现指令到二进制代码的转换
    :param instruction:
    :return: instruction：
    """
    for k, v in CSS_instruction.items():
        if k == instruction[0]:
            instruction[0] = v[0]
            instruction.append(v[1])
            rs2 = findRegId(instruction[1])
            op = int(instruction[0], 2)
            imm = "{:06b}".format(int(instruction[2]))
            imm = int(imm, 2)
            func3 = int(instruction[3], 2)
            print(instruction)
            instruction = [op, rs2, imm, func3]
            return CSS_type_Format(instruction)


def CIW_type_Format(data_list):
    return "{:03b}{:08b}{:03b}{:02b}".format(data_list[3], data_list[2], data_list[1], data_list[0])


def CIW_convertInstruction2Binary(instruction):
    """
    用于实现指令到二进制代码的转换
    :param instruction: 分割好的指令，如：['c.addi4spn', '1', '32']
    :return: instruction：转换为二进制代码的指令，如：['00', '1', '32', '000']
    """
    for k, v in CIW_instruction.items():
        if k == instruction[0]:
            instruction[0] = v[0]
            instruction.append(v[1])
            op = int(instruction[0], 2)
            func3 = int(instruction[3], 2)
            rd_1 = int(instruction[1])
            imm = "{:08b}".format(int(instruction[2]))
            imm = int(imm, 2)
            instruction = [op, rd_1, imm, func3]
            print(instruction)
            return CIW_type_Format(instruction)


def CL_type_Format(data_list):
    return "{:03b}{:03b}{:03b}{:02b}{:03b}{:02b}".format(data_list[5], data_list[4], data_list[3], data_list[2],
                                                         data_list[1], data_list[0])


def CL_convertInstruction2Binary(instruction):
    """
    用于实现指令到二进制代码的转换
    :param instruction:['c.fld', '2', '32', '3']
    :return: instruction：00010100011000001
    """
    for k, v in CL_instruction.items():
        if k == instruction[0]:
            instruction[0] = v[0]
            instruction.append(v[1])
            # instruction_change = list(map(int, instruction[1:-1]))
            op = int(instruction[0], 2)
            rd_1 = int(instruction[1])
            rs_1 = int(instruction[2])
            func = int(instruction[4], 2)
            imm = "{:05b}".format(int(instruction[3]))
            imm_high = int(imm[:2], 2)
            imm_low = int(imm[2:], 2)
            instruction = [op, rd_1, imm_high, rs_1, imm_low, func]
            print(instruction)
            return CL_type_Format(instruction)


def CS_type_Format(data_list):
    return "{:03b}{:03b}{:03b}{:02b}{:03b}{:02b}".format(data_list[5], data_list[4], data_list[3], data_list[2],
                                                         data_list[1], data_list[0])


def CS_convertInstruction2Binary(instruction):
    """
    用于实现指令到二进制代码的转换
    :param instruction:
    :return: instruction：
    """
    for k, v in CS_instruction.items():
        if k == instruction[0]:
            instruction[0] = v[0]
            instruction.append(v[1])
            rs_2 = int(instruction[1])
            rs_1 = int(instruction[2])
            op = int(instruction[0], 2)
            func3 = int(instruction[4], 2)
            imm = "{:05b}".format(int(instruction[3]))
            imm_high = int(imm[:2], 2)
            imm_low = int(imm[2:], 2)
            instruction = [op, rs_2, imm_high, rs_1, imm_low, func3]
            print(instruction)
            return CS_type_Format(instruction)


def CA_type_Format(data_list):
    return "{:06b}{:03b}{:02b}{:03b}{:02b}".format(data_list[4], data_list[3], data_list[2], data_list[1], data_list[0])


def CA_convertInstruction2Binary(instruction):
    """
    用于实现指令到二进制代码的转换
    :param instruction:
    :return: instruction：
    """
    for k, v in CA_instruction.items():
        if k == instruction[0]:
            # instruction[0] = v[0]
            # instruction.append(v[1])
            op = int(v[0], 2)
            func2 = int(v[1], 2)
            func6 = int(v[2], 2)
            rd_1 = int(instruction[1])
            rs2_1 = int(instruction[2])
            instruction = [op, rs2_1, func2, rd_1, func6]
            print(instruction)
            return CA_type_Format(instruction)


def CB_type_Format(data_list):
    return "{:03b}{:03b}{:03b}{:05b}{:02b}".format(data_list[4], data_list[3], data_list[2], data_list[1], data_list[0])


def CB_convertInstruction2Binary(instruction):
    """
    用于实现指令到二进制代码的转换
    :param instruction:
    :return: instruction：
    """
    for k, v in CB_instruction.items():
        if k == instruction[0]:
            # instruction[0] = v[0]
            # instruction.append(v[1])
            if k == 'c.srli' or k == 'c.srai' or k == 'c.andi':
                op = int(v[0], 2)
                func2 = v[1]
                func3 = int(v[2], 2)
                rd_1 = int(instruction[1])
                imm = "{:05b}".format(int(instruction[2]))
                imm_high = imm[0]
                imm_low = int(imm[1:], 2)
                instruction = [op, imm_low, rd_1, int(imm_high + func2, 2), func3]
                print(instruction)
            else:
                op = int(v[0], 2)
                func3 = int(v[1], 2)
                rs1_1 = int(instruction[1])
                imm = "{:08b}".format(int(instruction[2]))
                imm_high = int(imm[:5], 2)
                imm_low = int(imm[5:], 2)
                instruction = [op, imm_high, rs1_1, imm_low, func3]
            print(instruction)
            return CB_type_Format(instruction)


def CJ_type_Format(data_list):
    return "{:03b}{:011b}{:02b}".format(data_list[2], data_list[1], data_list[0])


def CJ_convertInstruction2Binary(instruction):
    """
    用于实现指令到二进制代码的转换
    :param instruction:
    :return: instruction：
    """
    for k, v in CJ_instruction.items():
        if k == instruction[0]:
            instruction[0] = v[0]
            instruction.append(v[1])
            print(instruction)
            op = int(instruction[0], 2)
            imm = int(instruction[1])
            func3 = int(instruction[2], 2)
            instruction = [op, imm, func3]
            print(instruction)
            return CJ_type_Format(instruction)


def confirmInstructionFormat(command):
    """
    用于确定指令所属格式
    :param command: 指令，如c.addi4spn
    :return: 指令格式所属名称，如CIW_instruction
    """
    for k, v in instructionFormat.items():
        for commandTemp in v:
            if commandTemp == command:
                return k




"""
switch存储对应的转换函数地址，用于实现switch功能
"""
switch = {'CR_instruction': CR_convertInstruction2Binary,
          'CI_instruction': CI_convertInstruction2Binary,
          'CSS_instruction': CSS_convertInstruction2Binary,
          'CIW_instruction': CIW_convertInstruction2Binary,
          'CL_instruction': CL_convertInstruction2Binary,
          'CS_instruction': CS_convertInstruction2Binary,
          'CA_instruction': CA_convertInstruction2Binary,
          'CB_instruction': CB_convertInstruction2Binary,
          'CJ_instruction': CJ_convertInstruction2Binary}

"""
字典key, value值互换函数
"""
def reverse_dict(d):
    reverse_d = {}
    for k, v in d.items():
        if isinstance(v, list):
            for temp in v:
                reverse_d[temp] = k
        else:
            reverse_d[v] = k
    return reverse_d

"""
存储寄存器号到寄存器ABI名的映射
"""
index2RegABIName = {
    0: "zero",  # 0
    1: "ra",
    2: "sp",
    3: "gp",
    4: "tp",
    5: "t0",
    6: "t1",
    7: "t2",
    8: ["s0", "fp"],
    9: "s1",
    10: "a0",
    11: "a1",
    12: "a2",
    13: "a3",
    14: "a4",
    15: "a5",
    16: "a6",
    17: "a7",
    18: "s2",
    19: "s3",
    20: "s4",
    21: "s5",
    22: "s6",
    23: "s7",
    24: "s8",
    25: "s9",
    26: "s10",
    27: "s11",
    28: "t3",
    29: "t4",
    30: "t5",
    31: "t6",
    32: "t7",
}

"""
存储寄存器号到寄存器名的映射
"""
index2RegName = {
    0: "x0",
    1: "x1",
    2: "x2",
    3: "x3",
    4: "x4",
    5: "x5",
    6: "x6",
    7: "x7",
    8: "x8",
    9: "x9",
    10: "x10",
    11: "x11",
    12: "x12",
    13: "x13",
    14: "x14",
    15: "x15",
    16: "x16",
    17: "x17",
    18: "x18",
    19: "x19",
    20: "x20",
    21: "x21",
    22: "x22",
    23: "x23",
    24: "x24",
    25: "x25",
    26: "x26",
    27: "x27",
    28: "x28",
    29: "x29",
    30: "x30",
    31: "x31",
    32: "x32",
}

"""
存储名到寄存器号的映射
"""
regABIName2Index = reverse_dict(index2RegABIName)
regName2Index = reverse_dict(index2RegName)



